/*
 *  Copyright 2011 Alexey Andreev.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package org.xthl.core;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.nop.core.BeanScope;
import org.nop.core.ManagedBean;
import org.nop.sql.DataManager;
import org.nop.sql.DataResult;
import org.nop.sql.QueryBuilder;
import org.nop.util.Injected;
import org.xthl.core.api.MenuCustomItem;
import org.xthl.core.api.MenuItem;
import org.xthl.core.api.MenuLogic;
import org.xthl.core.api.MenuSpecialItem;
import org.xthl.core.data.MenuItemSource;

/**
 *
 * @author Alexey Andreev
 */
@ManagedBean(iface = MenuLogic.class, scope = BeanScope.REQUEST)
public class MenuLogicImpl implements MenuLogic {
    private DataManager dataManager;
    private QueryBuilder qb;
    
    @Injected
    public MenuLogicImpl(DataManager dataManager) {
        this.dataManager = dataManager;
        this.qb = dataManager.getQueryBuilder();
    }

    @Override
    public int createCustomItem(String title, String url) {
        MenuItemSource item = qb.get(MenuItemSource.class);
        DataResult result = dataManager.exec(qb.with(item)
                .fetch(qb.max(item.position())));
        result.next();
        int pos = result.getInt(1) + 1;
        int id = dataManager.nextInt(MenuItemSource.ID_SEQUENCE);
        dataManager.exec(qb.insertInto(item)
                .field(item.id(), id)
                .field(item.enabled(), false)
                .field(item.type(), MenuItemSource.CUSTOM_TYPE)
                .field(item.target(), url)
                .field(item.title(), title)
                .field(item.position(), pos));
        return id;
    }

    @Override
    public void deleteCustomItem(int id) {
        MenuItemSource item = qb.get(MenuItemSource.class);
        dataManager.exec(qb.with(item)
                .filter(item.id().eq(id))
                .delete());
    }

    @Override
    public void enableItems(Set<Integer> itemIds, boolean enable) {
        MenuItemSource item = qb.get(MenuItemSource.class);
        dataManager.exec(qb.with(item)
                .filter(item.id().inNumbers(itemIds))
                .set(item.enabled(), enable));
    }
    
    private Class<?> getItemClass(String name) {
        try {
            return Class.forName(name);
        } catch (ClassNotFoundException ex) {
            return null;
        }
    }
    
    private MenuItem getItem(DataResult result) {
        String type = result.getString(1);
        if (type.equals(MenuItemSource.SPECIAL_TYPE)) {
            MenuSpecialItem item = new MenuSpecialItem();
            item.setId(result.getInt(2));
            item.setPosition(result.getInt(3));
            item.setEnabled(result.getBoolean(4));
            item.setTitle(result.getString(5));
            item.setGeneratorType(getItemClass(result.getString(6)));
            if (item.getGeneratorType() == null) {
                return null;
            }
            return item;
        } else if (type.equals(MenuItemSource.CUSTOM_TYPE)) {
            MenuCustomItem item = new MenuCustomItem();
            item.setId(result.getInt(2));
            item.setPosition(result.getInt(3));
            item.setEnabled(result.getBoolean(4));
            item.setTitle(result.getString(5));
            item.setUrl(result.getString(6));
            return item;
        } else {
            return null;
        }
    }

    @Override
    public List<MenuItem> getItems() {
        MenuItemSource item = qb.get(MenuItemSource.class);
        DataResult result = dataManager.exec(qb.with(item)
                .sortAsc(item.position())
                .fetch(item.type(), item.id(), item.position(), item.enabled(),
                item.title(), item.target()));
        List<MenuItem> dtos = new ArrayList<MenuItem>();
        while (result.next()) {
            dtos.add(getItem(result));
        }
        return dtos;
    }

    @Override
    public MenuItem getItem(int itemId) {
        MenuItemSource item = qb.get(MenuItemSource.class);
        DataResult result = dataManager.exec(qb.with(item)
                .filter(item.id().eq(itemId))
                .fetch(item.type(), item.id(), item.position(), item.enabled(),
                item.title(), item.target()));
        return result.next() ? getItem(result) : null;
    }

    @Override
    public List<MenuItem> getEnabledItems() {
        MenuItemSource item = qb.get(MenuItemSource.class);
        DataResult result = dataManager.exec(qb.with(item)
                .filter(item.enabled().isTrue())
                .sortAsc(item.position())
                .fetch(item.type(), item.id(), item.position(), item.enabled(),
                item.title(), item.target()));
        List<MenuItem> dtos = new ArrayList<MenuItem>();
        while (result.next()) {
            dtos.add(getItem(result));
        }
        return dtos;
    }

    @Override
    public void moveItem(int id, int targetPosition) {
        MenuItemSource item = qb.get(MenuItemSource.class);
        DataResult result = dataManager.exec(qb.with(item)
                .filter(item.id().eq(id))
                .fetch(item.position()));
        result.next();
        int currentPosition = result.getInt(1);
        if (currentPosition > targetPosition) {
            dataManager.exec(qb.with(item)
                    .filter(item.position().ge(targetPosition))
                    .filter(item.position().le(currentPosition))
                    .set(item.position(), qb.cond()
                        .when(item.position().ne(currentPosition),
                        item.position().add(qb.wrap(1)))
                        .otherwise(qb.wrap(targetPosition))));
        } else if (currentPosition < targetPosition) {
            dataManager.exec(qb.with(item)
                    .filter(item.position().ge(currentPosition))
                    .filter(item.position().le(targetPosition))
                    .set(item.position(), qb.cond()
                        .when(item.position().ne(currentPosition),
                        item.position().sub(qb.wrap(1)))
                        .otherwise(qb.wrap(targetPosition))));
        }
    }
    
    private String getItemType(int itemId) {
        MenuItemSource item = qb.get(MenuItemSource.class);
        DataResult result = dataManager.exec(qb.with(item)
                .filter(item.id().eq(itemId))
                .fetch(item.type()));
        if (!result.next()) {
            throw new IllegalArgumentException("Menu item not found: " + itemId);
        }
        return result.getString(1);
    }

    @Override
    public void setItemTitle(int id, String title) {
        getItemType(id);
        MenuItemSource item = qb.get(MenuItemSource.class);
        dataManager.exec(qb.with(item)
                .filter(item.id().eq(id))
                .set(item.title(), title));
    }

    @Override
    public void setCustomItemUrl(int id, String url) {
        if (!getItemType(id).equals(MenuItemSource.CUSTOM_TYPE)) {
            throw new IllegalArgumentException("Menu item #" + id + " is not custom");
        }
        MenuItemSource item = qb.get(MenuItemSource.class);
        dataManager.exec(qb.with(item)
                .filter(item.id().eq(id))
                .set(item.target(), url));
    }
}
